package org.duang.db.sql.parser;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.duang.db.IdEntity;
import org.duang.db.annotation.Vo;
import org.duang.db.annotation.VoColl;
import org.duang.db.common.Query;
import org.duang.db.common.Update;
import org.duang.db.mongo.Operator;
import org.duang.db.mongo.parser.EncodeConvetor;
import org.duang.db.mongo.parser.encode.Encoder;
import org.duang.db.sql.SqlObject;
import org.duang.db.sql.parser.encode.SqlCollectionEncoder;
import org.duang.db.sql.parser.encode.SqlDBObjectEncoder;
import org.duang.db.sql.parser.encode.SqlEncoder;
import org.duang.db.sql.parser.encode.SqlPropertyEncoder;
import org.duang.kit.ClassKit;
import org.duang.kit.ToolsKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mongodb.DBObject;

/**
 * Entity Convetor SqlObject Factory
 * @author laotang
 *
 */
public class SqlEncodeConvetor {

	private final static Logger logger = LoggerFactory.getLogger(SqlEncodeConvetor.class);
	public final static String ID_FIELD = "id";
	private static final String SPACE = " ";
	private static final String SEPARATOR = ",";
	
	public static SqlObject convetorIdentity(Object obj, boolean isInsert) {
		if(ToolsKit.isEmpty(obj)){
			throw new NullPointerException("Entity Convetor SqlObject Fail: " + obj.getClass().getCanonicalName() + " is null!");
		}
		IdEntity idEntity = (IdEntity)obj;
		String id = idEntity.getId();
		if(!isInsert && ToolsKit.isEmpty(id)){
			isInsert = true;
			id = ToolsKit.builderObjectId();
		}
//			ToolsKit.setObjectId2Thread(id);
//		} 
//		if(!isInsert) {
//			id = ToolsKit.getObjectIdByThread();
//			// 如果当前线程中有ObjectId, 则为新增，如果没有ObjectId的话，则为修改
//			if(ToolsKit.isNotEmpty(id)){
//				isInsert = true;
//				ToolsKit.removeObjectIdByThread();	// 删除当前线程中的值
//			} else {
//				id = idEntity.getId();
//			}
//		}
		
		Class<?> cls = obj.getClass();
		String tableName = ClassKit.getBeanName(cls, true);
		StringBuilder sql = new StringBuilder();
		if(isInsert){
			sql.append("insert into ").append(tableName).append(" "); //.append(" values (");
		} else {
			sql.append("update ").append(tableName).append(" ");
		}
		Field[] fields = ClassKit.getFields(cls);
		SqlObject sobj  = new SqlObject();
		StringBuilder sqlItem = new StringBuilder();
		StringBuilder sqlFieldItem = new StringBuilder();
		List<Object> params = new ArrayList<Object>();
		if(ToolsKit.isNotEmpty(fields)){
			for (int i = 0; i < fields.length; i++) {
				Field field = fields[i];
				if(field.isAnnotationPresent(Vo.class ) || 
						field.isAnnotationPresent(VoColl.class) || 
						field.getName().equals(IdEntity.ID_FIELD) ||
							field.getName().equals(ID_FIELD)){		//ID字段放在最后
							continue;
				}
				Encoder encoder = EncodeConvetor.parser(obj, field);
				if(!encoder.isNull() && !encoder.isTran()){	
					if(isInsert){
						sqlFieldItem.append(encoder.getFieldName()).append(",");
						sqlItem.append("?").append(",");
					} else {
						sqlItem.append(encoder.getFieldName()).append("=?").append(",");
					}
					params.add(encoder.getValue());
				}
			}
		}
		if(isInsert){
			sqlFieldItem.append(IdEntity.ID_FIELD);
			sql.append("(").append(sqlFieldItem).append(")").append(" values (").append(sqlItem).append("?)");
		} else {
			sql.append(" set ").append(sqlItem.deleteCharAt(sqlItem.length()-1)).append(" where ").append(IdEntity.ID_FIELD).append("=?");
		}
		params.add(id);	//最后添加ID参数
		sobj.setSql(sql.toString());
		sobj.setParams(params);
		return sobj;
	}
	
	
	public static SqlObject convetor(Class<?> clazz, Object objs) {
		if(ToolsKit.isEmpty(objs)){
			throw new NullPointerException("Entity Convetor SqlObject Fail:  Objs is null!");
		}
		SqlObject sqlObj = null;
		 if (objs instanceof IdEntity) {
			 return convetorIdentity(objs, false);
		} else {
			DBObject dboObj  = null;
			Class<?> flagCls = null;
			Query query = null;
			if(objs instanceof Query){
				query = ((Query)objs);
				dboObj = query.getQueryObj();
				flagCls =  Query.class;
			} else if(objs instanceof Update){
				dboObj = ((Update)objs).getUpdateObj();
				flagCls = Update.class;
			} 			
//			logger.debug("##############: dboObj: " + dboObj.toString());
			List<SqlObject> sqlObjs = new ArrayList<SqlObject>();
			for(Iterator<String> it = dboObj.keySet().iterator(); it.hasNext();){
				String key = it.next();
				Object obj = dboObj.get(key);
				SqlEncoder ecoder = parser(key, key, obj);
				sqlObjs.add( builderSqlObject(flagCls, key, ecoder.getValue()) );
			}
			sqlObj = builderSqlObject(flagCls, "", sqlObjs);
			StringBuilder sql = new StringBuilder();
			if(ToolsKit.isNotEmpty(query)){
				sql.append("select ");
				StringBuilder fieldStrs = new StringBuilder();
				if(ToolsKit.isNotEmpty(query.getDBFields())){
					for(Iterator<String> it = query.getDBFields().keySet().iterator(); it.hasNext();){
						String key = it.next();
						fieldStrs.append(key).append(",");
					}
				}
				if(fieldStrs.length()> 1){
					fieldStrs.deleteCharAt(fieldStrs.length()-1);
				} else {
					fieldStrs.append("*");
				}
				sql.append(fieldStrs.toString()).append(" from ").append(ClassKit.getBeanName(clazz, true)).append(" where ").append(sqlObj.getSql());
			}
			sqlObj.setSql(sql.toString());
			logger.debug("##############: sqlObj: " + sqlObj.getSql()+"                        "+sqlObj.getParams());
		}
		return sqlObj;
	}
	
	private static SqlObject builderSqlObject(Class<?> flagCls, String opt , List<SqlObject> list) {
		if(flagCls.equals(Query.class)){
			opt = Operator.SQL_OPERATOR_MAP.get(opt);
			if(ToolsKit.isEmpty(opt)) opt = Operator.SQL_OPERATOR_MAP.get(Operator.AND);
		} else if (flagCls.equals(Update.class)){
			opt = SEPARATOR;
		}
		if(ToolsKit.isEmpty(list)) throw new NullPointerException();
		StringBuilder sql = new StringBuilder();
		int size = list.size();
		List<Object> params = new ArrayList<Object>(size);
		for(int i=0; i<size; i++){
			SqlObject obj = list.get(i);
			
			sql.append(obj.getSql());
			if(i < (size-1)){
				sql.append(SPACE).append(opt).append(SPACE);	
			}
			params.addAll(obj.getParams());
		}
		return new SqlObject(sql.toString(), params);	 
	}
	
	
	
	
	public static SqlEncoder parser(String key, String opt, Object obj){
		SqlEncoder encoder = null;
		if(obj instanceof DBObject) {
			encoder = new SqlDBObjectEncoder(key, opt, obj);
		} else if(obj instanceof Collection){
			encoder = new SqlCollectionEncoder(key, opt, obj);
		} else {
			encoder = new SqlPropertyEncoder(key, opt, obj);
		}
		return encoder;
		 
	}
}
